#ifndef __SOCKETBASE__
#define __SOCKETBASE__


#include "SocketStruct.h"

const int SB_MAXHOSTNAME         = 64;
const int SB_MAX_UDP_PACKET_SIZE = 8192;
const int sixsixsix              = 666;
const float f_sixsixsix          = 666.666f;
using namespace std;
class SocketBase
{
protected:
	int			little_endian;
	int			global_message;
	int			quiet;
	int			use_udp;

	SocketBase();
	~SocketBase();

	void		getTime(SM_TIME_T *val);
	float		timevalDifference(const		SM_TIME_T& tv2,
							    const		SM_TIME_T& tv1
							);
	char *		longToDotFormat(long addr);
	int			pollOnFDWithTimeout(SOCKET			poll_fd,
								const struct	timeval &timeout
							);
	int			bytesAvailableOnFD(int fd);
	int			byteSwapLongBufferFromNet(SocketBuf *sb, int data_size);
	int			byteSwapLongBufferToNet	(SocketBuf *sb, int data_size);

	int			readPacketLength(SocketStruct *current_socket,
							float timeout
						   );
	SocketBuf*  readPacketDataType(SocketStruct *current_socket,
								int bytes_in_packet,
								float timeout
							);
	SocketBuf*	readPacketData(SocketStruct *current_socket,
							SocketBuf *sbuf,
							float timeout
						);
	SocketBuf*	_readWithPollAndTimeout(SocketStruct *current_socket,
									const struct timeval &poll_timeout,
									float read_timeout_float,
									int use_udp_for_read,
									int use_multicast_for_read = 0
								);

	int			recoverReadPacketLength(SocketStruct *current_socket,
										float timeout
									);
	SocketBuf*	recoverReadPacketDataType(SocketStruct *current_socket,
										  float timeout
									);
	SocketBuf*	recoverReadPacketData(SocketStruct *current_socket,
										float timeout
									);
	SocketBuf*	_recoverFromReadError(SocketStruct *current_socket,
											float read_timeout_float
										);

	int			_writeWithTimeout(SocketStruct *current_socket,
								SocketBuf *sbuf,
								float timeout,
								int use_udp_for_write,
								int use_multicast = 0,
								struct sockaddr *address = 0
							);

public:
	enum Socket_Messages 
	{
		MSG_NO_ERROR,
		ERR_DURING_SELECT,
		MSG_SS_ACCEPT_CONNECTION,
		MSG_SS_READ_FROM_CURRENT_SOCKET,
		MSG_NO_SOCKET_READY_TO_READ,
		MSG_SOCKET_READY_TO_READ,
		MSG_SOCKET_NOT_READY_TO_READ,
		ERR_UNKNOWN_HOST,
		ERR_CREATING_SOCKET,
		ERR_BINDING_SOCKET,
		ERR_LISTENING_ON_SOCKET,
		ERR_LISTENING_SOCKET_NOT_OPEN,
		ERR_LISTENING_SOCKET_FAILED_ACCEPT,
		MSG_LISTENING_SOCKET_NO_PENDING_CONNECTIONS,
		MSG_MAXIMUM_NUMBER_OF_CONNECTIONS,
		ERR_SHUTTING_DOWN_LISTENING_SOCKET,
		ERR_CLOSING_LISTENING_SOCKET,
		ERR_SHUTTING_DOWN_CONNECTED_SOCKET,
		ERR_CLOSING_CONNECTED_SOCKET,
		ERR_DELETING_CONNECTED_SOCKET,
		ERR_UNSUBSCRIBING_FROM_MULTICAST_GROUP,
		ERR_UDP_NO_SERVER_INFORMATION,
		ERR_UDP_CREATING_SOCKET,
		ERR_UDP_BINDING_SOCKET,
		ERR_UDP_CONNECTING_SOCKET,
		ERR_UDP_CLIENT_NO_RESPONSE,
		ERR_UDP_SERVER_NO_RESPONSE,
		ERR_UDP_RECEIVE_FAILED,
		ERR_UDP_PACKET_TOO_LARGE,
		ERR_UDP_SEND_FAILED,
		ERR_MULTICAST_INVALID_ADDRESS,
		ERR_MULTICAST_CREATING_SOCKET,
		ERR_MULTICAST_REUSING_ADDRESS,
		ERR_MULTICAST_GETTING_NETWORK_INTERFACE,
		ERR_MULTICAST_BINDING_SOCKET,
		ERR_MULTICAST_SUBSCRIBING_TO_GROUP,
		ERR_MULTICAST_SEND_FAILED,
		ERR_CURRENT_SOCKET_NOT_OPEN,
		ERR_CURRENT_SOCKET_CLOSED,
		ERR_CONNECTING_TO_SERVER,
		ERR_ALREADY_CONNECTED_TO_SERVER,
		ERR_TIMEOUT_READING_PACKET_LENGTH,
		ERR_SIGPIPE_READING_PACKET_LENGTH,
		ERR_TIMEOUT_READING_PACKET_DATA_TYPE,
		ERR_SIGPIPE_READING_PACKET_DATA_TYPE,
		ERR_TIMEOUT_READING_PACKET,
		ERR_SIGPIPE_READING_PACKET,
		ERR_TIMEOUT_WRITING_PACKET,
		ERR_SIGPIPE_WRITING_PACKET,
		ERR_DATA_TYPE_DOES_NOT_MATCH_NUM_BYTES
	};

	int				getGlobalMessage();

	const char *	getMessageString(int message_num);

	int				getQuiet();
	void			setQuiet(int on_or_off);

	int				getUsingSysVSignals();
	void			setUsingSysVSignals(int on_or_off);

	/* Helper routine */
	long			getLocalIPAddress();
};

#endif
